from helpFunc import *
import socket,select,os,time
from connbase import *
from ser import *

class tcpRePeer(tcpReBase):
    def __init__(self,dataPort,numPort,maxConn,cachePerConn,ss,bufSize):
        self.dataPort = dataPort
        self.numPort = numPort    
        tcpReBase.__init__(self,dataPort,numPort,maxConn,cachePerConn,bufSize)     
        self.connectPollingMap = {}
        self.ssPort = ss

    def start(self,onePakcLen,totalSendLen,
              packEffectTime,timeoutInter,lp,k):
        import threading
        def ww():
            a = ser(self.dataPort,self.numPort,onePakcLen,totalSendLen,
                    packEffectTime,timeoutInter,lp,k)    
            while True:
                a.work()                 
        self.t = t = threading.Thread(target=ww)
        t.setDaemon(True)
        t.start()  
        super().iniSock()
        while True:
            self.dowork()

    def dowork(self):                      
        rl = [self.connSock,self.numSock]
        if len(self.peerBuf)<tcpReadLen:
            rl += self.getReadSocks()

        wl = self.getWriteSocks()+list(self.connectPollingMap.keys())
        if self.peerBuf and self.sockWriteLen>0:
            wl.append(self.connSock)

        el = self.connectPollingMap.keys()
        rl,wl,el = select.select(rl,wl,el,1)

        for sock in rl:
            if sock == self.numSock:
                self.numSockRecv()
                continue

            if sock == self.connSock:
                ss = sock.recv(tcpReadLen)                
                msgList = self.dealData( ss)
                for one in msgList:
                    ty,id,da = self.decodeMsg(one)  
                    if  ty==bufChange_g:
                        aa = struct.unpack('i',da)[0]
                        self.dealBufChange(aa)
                    
                    if  ty==ping_g:
                        print ('ping')
                        dd = self.makeMsg(ping_g,id,b'\x00')                          
                        self.sendMsg(dd)  
                        
                    if  ty==askConn_g:
                        print ('ask conn')
                        if self.connNum > self.maxNum:
                            print ('too much',self.connNum)
                            dd = self.makeMsg(connBack_g,id,b'\x00')                          
                            self.sendMsg(dd)                              
                        try:
                            s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)                                                                                             
                            s.setblocking(0)
                            s.connect_ex(('127.0.0.1',self.ssPort))
                            self.connectPollingMap[s]={'id':id}

                        except Exception as e:
                            print (e)
                            s.close()
                            dd = self.makeMsg(connBack_g,id,b'\x00')    
                            self.sendMsg(dd)    
                    else:
                        self.dealConnsockNormal(id, ty,da)
                continue
            self.dealProxysocks(sock)
        for sock in wl:
            if sock == self.connSock:
                n = self.connSock.send(self.peerBuf[:self.sockWriteLen])
                self.peerBuf = self.peerBuf[n:]
                self.sockWriteLen -= n
                continue            
            if sock in self.connectPollingMap:
                id = self.connectPollingMap[sock]['id']
                del self.connectPollingMap[sock]
                dd = self.makeMsg(connBack_g,id,b'\x01')    
                self.sendMsg(dd)
                self.proxySocks[sock] = {'id':id,'data':b'','peerclose':False,'peerFull':False,'tellMyFull':False}
                self.idMap[id] = {'sock':sock}
                self.connNum +=1 
                print ('accept',self.connNum )
                continue
            self.dealWritesocks(sock)

        for sock in el:
            if sock in self.connectPollingMap:
                sock.close()
                id = self.connectPollingMap[sock]['id']
                del self.connectPollingMap[sock]                
                dd = self.makeMsg(connBack_g,id,b'\x00')      
                self.sendMsg(dd)                     

if __name__ == '__main__':
    import sys
    ar = sys.argv
    if len(ar)>1 :
        s = ar[1].encode()
        import base64,json
        j = base64.b64decode(s)
        m = json.loads(j.decode())
        maxConn=m['maxConn'] 
        cachePeerConn =m['cachePeerConn']
        ssPort=m['ssPort'] 
        oneLen=m['oneLen'] 
        tLen=m['tLen'] 
        bufsize=m['bufsize'] 
        effTime=m['effTime'] 
        inter=m['inter'] 
        port=m['port']     
        k=m['key'].encode()   
        pp =  findNPorts(2,ty=socket.SOCK_STREAM)
        t = tcpRePeer(pp[0],pp[1],maxConn,cachePeerConn,ssPort,bufsize)
        t.start(oneLen,tLen,effTime,inter,port,k)
    else:
        l = findNPorts(2,socket.SOCK_STREAM)
        t = tcpRePeer(l[0],l[1],500,200*1024,con_ssPort,con_connBufSize)
        t.start(serverPackLen,serverSenLen,
                con_packEffectTime,con_timeoutInternal,
                 22,b'123456')
